<template>
    <li 
        ref="dragItemRef"
        class="drag-item"
        draggable="true"
        @drop.prevent.self
        @dragstart.self="dragstart"
        style="background-color: antiquewhite;align-items: center;list-style: none;"
        :data-key="dataKey"
    >
        <slot></slot>
    </li>
</template>

<script setup lang="ts">
import { inject, onBeforeUnmount, onMounted, ref, defineProps } from 'vue';
import dragImageBase64 from './drag-image';
import { DragContext, DragProvider } from './constants';
import useDocumentEvent from './hooks/useDocumentEvent';

defineProps<{
    dataKey: string
}>()

const dragImage = new Image()
dragImage.src = dragImageBase64

const context = inject<DragContext>(DragProvider)
const dragItemRef = ref<HTMLElement>()

let targetNode: HTMLElement | null = null
let cloneNode: HTMLElement | null = null
const isDraging = ref(false)
const dragInfo = ref({
    clientX: 0,
    clientY: 0,
    offsetX: 0,
    offsetY: 0,
    transform: {
        x: 0,
        y: 0
    }
})

useDocumentEvent({
    onDragover(ev) {
        ev.preventDefault()
        if (cloneNode) {
        // this.dragElement!.style.visibility = 'hidden'
        const left = ~~(ev.clientX - dragInfo.value.offsetX)
        const top = ~~(ev.clientY - dragInfo.value.offsetY)
        cloneNode.style.transform = 'translate3d( ' + left + 'px ,' + top + 'px,0)'
            dragInfo.value.transform = {
                x: left,
                y: top
            }
        }
    },
    onDragend() {
        clearDrag()
    },
})

function dragstart(ev: DragEvent) {
    dataTransfer(ev)
    
    dragInfo.value.clientX = ev.clientX
    dragInfo.value.clientY = ev.clientY
    dragInfo.value.offsetX = ev.offsetX
    dragInfo.value.offsetY = ev.offsetY

    console.log('offsetY', ev.offsetY);
    
    
    targetNode = ev.target as HTMLElement
    cloneNode = document.createElement('div')

    const _cloneNodeTarget = targetNode?.cloneNode(true) as HTMLElement
    const { left, top } = targetNode.getBoundingClientRect()
    dragInfo.value.offsetX = ev.clientX - left
    dragInfo.value.offsetY = ev.clientY - top

    _cloneNodeTarget.style.transform = 'translate3d(0,0,0)'
    _cloneNodeTarget.style.position = 'static'
    _cloneNodeTarget.style.width = `${targetNode.offsetWidth}px`
    _cloneNodeTarget.style.height = `${targetNode.offsetHeight}px`

    cloneNode.appendChild(_cloneNodeTarget)

    cloneNode.style.position = 'fixed'
    cloneNode.style.top = '0'
    cloneNode.style.left = '0'
    
    cloneNode.style.zIndex = '9999'
    cloneNode.style.boxShadow = '5px 5px 15px rgba(0, 0, 0, .1)'
    cloneNode.style.pointerEvents = 'none'
    cloneNode.style.transform = `translate3d(${left}px, ${top}px, 0)`

    document.body.appendChild(cloneNode)

    isDraging.value = true
}

// function dragenter(e: DragEvent) {
//     if(!isDraging.value) {
//         return
//     }
// }

function dataTransfer(ev: DragEvent) {
    ev.dataTransfer?.setData('text', '')
    ev.dataTransfer?.setDragImage(dragImage, 0, 0)
}

function clearDrag() {
    if(!isDraging.value || !cloneNode || !targetNode) {
        return
    }

    const { top, left } = targetNode.getBoundingClientRect()

    cloneNode.animate([
        { 
            transform: `translate(${dragInfo.value.transform.x}px, ${dragInfo.value.transform.y}px)`, 
        },
        { 
            transform: `translate(${left}px, ${top}px)`, 
        }
    ], {
        duration: 300,
        easing: 'ease-in-out'
    })
    
    setTimeout(() => {
        cloneNode?.remove()
        targetNode = null
        cloneNode = null
        isDraging.value = false
        context?.dragEnd()
    }, 300)
    
}

onMounted(() => {
    if(dragItemRef.value) {
        context?.register(dragItemRef.value)
    }
})

onBeforeUnmount(() => {
    if(dragItemRef.value) {
        context?.deregistration(dragItemRef.value)
    }
})
</script>